﻿using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core;

using Newtonsoft.Json;
using PKISharp.WACS.Clients.DNS;
using PKISharp.WACS.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Aliyun.Acs.Alidns.Model.V20150109;
using Serilog;
using Nager.PublicSuffix;

[assembly: SupportedOSPlatform("windows")]

namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
{
    internal sealed class AliDns : DnsValidation<AliDns>
    {

        private readonly IProxyService _proxyService;

        private readonly string? _apiSecret;
        private readonly string? _apiKeyID;
        IClientProfile profile;
        IAcsClient client;
        DomainParseService _domainParser;
        public AliDns(
             LookupClientProvider dnsClient,
             ILogService log,
             IProxyService proxy,
             ISettingsService settings,
             DomainParseService domainParser,
             SecretServiceManager ssm,
             AliDnsOptions options) : base(dnsClient, log, settings)
        {
            _proxyService = proxy;
            _apiKeyID = options.AccessKeyID;
            _apiSecret = ssm.EvaluateSecret(options.AccessKeySecret);
            profile = DefaultProfile.GetProfile("cn-hangzhou", _apiKeyID, _apiSecret);
            client = new DefaultAcsClient(profile);
            _domainParser = domainParser;
        }
        private static readonly Dictionary<string, string> _recordsMap = new Dictionary<string, string>();

        public override async Task<bool> CreateRecord(DnsValidationRecord record)
        {
            _log.Information("Creating Aliyun DNS verification record", record.Authority.Domain);
            var domain = _domainParser.GetRegisterableDomain(record.Authority.Domain);
            _log.Information("Aliyun Domain:", domain);
            var recordName = RelativeRecordName(domain, record.Authority.Domain);
            _log.Information("Aliyun RecordName:", recordName);
            AddDomainRecordRequest request = new AddDomainRecordRequest();
            request._Value = record.Value;
            request.Type = "TXT";
            request.RR = recordName;
            request.DomainName = domain;
            try
            {
                AddDomainRecordResponse response = client.GetAcsResponse(request);
                if (response == null || response.RecordId == null || string.IsNullOrWhiteSpace(response.RecordId))
                {
                    _log.Error("Empty or invalid response");
                    return false;
                }

                _recordsMap[record.Authority.Domain] = response.RecordId;
                return true;
            }
            catch (ServerException e)
            {
                _log.Error(e, e.Message, e.StackTrace);

            }
            catch (ClientException e)
            {
                _log.Error(e, e.Message, e.StackTrace);
            }
            return false;
        }

        public override async Task DeleteRecord(DnsValidationRecord record)
        {
            if (!_recordsMap.ContainsKey(record.Authority.Domain))
            {
                _log.Warning($"No record with name {record.Authority.Domain} was created");
                return;
            }

            _log.Information("Deleting AliDNS verification record");
            try
            {
                var created = _recordsMap[record.Authority.Domain];
                DeleteDomainRecordRequest request = new DeleteDomainRecordRequest();
                request.RecordId = created;
                var response = client.GetAcsResponse(request);
                if (response == null)
                {
                    _log.Warning("Failed to delete DNS verification record");
                    return;
                }

                _ = _recordsMap.Remove(record.Authority.Domain);

            }
            catch (Exception ex)
            {
                _log.Warning("Failed to delete DNS verification record");
                _log.Error(ex, ex.Message, ex.StackTrace);
            }

            return;
        }

    }
}